using SDK.Scripts.Utils;
using System;
using System.ComponentModel;
using System.Net;
using System.Net.Sockets;

namespace SDK.Scripts.Network
{
	public class UDSocket : Component
	{
		public struct SvrAddr
		{
			public string ip
			{
				get;
				set;
			}

			public int port
			{
				get;
				set;
			}

			public SvrAddr(string i = "0", int p = 0)
			{
				ip = i;
				port = p;
			}
		}

		public class StateObject
		{
			public byte[] buffer;

			public int recvBuffer;

			public SvrAddr addr
			{
				get;
				set;
			}

			public Socket socket
			{
				get;
				set;
			}

			public ushort recvSize
			{
				get;
				set;
			}

			public StateObject(Socket socket, SvrAddr addr, int bufferSize)
			{
				this.socket = socket;
				this.addr = addr;
				recvBuffer = bufferSize;
				buffer = new byte[recvBuffer];
				recvSize = 0;
			}

			public void Reset()
			{
				socket = null;
			}
		}

		public delegate void NetConnectEventHandler(object sender);

		public delegate void NetConnectErrorEventHandler(object sender);

		public delegate void NetDisConnectEventHandler(object sender);

		public delegate void NetRecvMsgEventHandler(object sender, byte[] msg, int len);

		public delegate void NetSendMsgEventHandler(object sender, int len);

		private static int MAX_BUFF_SIZE = 100000;

		private Socket _socket;

		private bool _isConnect;

		private AsyncCallback _connectCallback;

		private AsyncCallback _receiveCallback;

		private AsyncCallback _sendCallback;

		private static readonly object locker = new object();

		public bool IsConnected
		{
			get
			{
				if (_socket == null)
				{
					return false;
				}
				return _isConnect;
			}
		}

		public static event NetConnectEventHandler ConnectServer;

		public static event NetConnectErrorEventHandler ConnectError;

		public static event NetDisConnectEventHandler DisConnectServer;

		public static event NetRecvMsgEventHandler NetDataRecv;

		public static event NetSendMsgEventHandler NetDataSend;

		public bool Connect(string ip, int port)
		{
			SvrAddr addr = new SvrAddr(ip, port);
			addr.ip = ip;
			addr.port = port;
			if (string.Compare(addr.ip, string.Empty) == 0)
			{
				Debuger.LogWarning("warning : ip is null");
				return false;
			}
			return Connect(addr);
		}

		private bool Connect(SvrAddr addr)
		{
			try
			{
				string ip = addr.ip;
				AddressFamily addressFamily = AddressFamily.InterNetwork;
				_socket = new Socket(addressFamily, SocketType.Stream, ProtocolType.Tcp);
				_socket.NoDelay = true;
				IPEndPoint remoteEP = new IPEndPoint(IPAddress.Parse(ip), addr.port);
				StateObject state = new StateObject(_socket, addr, MAX_BUFF_SIZE);
				if (_connectCallback == null)
				{
					_connectCallback = ConnectCallback;
				}
				_socket.BeginConnect(remoteEP, _connectCallback, state);
			}
			catch (SocketException ex)
			{
				Debuger.LogError("connet error : " + ex.Message);
				OnConnectError();
				return false;
			}
			return true;
		}

		public void Close()
		{
			lock (locker)
			{
				if (_socket != null)
				{
					try
					{
						if (_socket.Connected)
						{
							_socket.Shutdown(SocketShutdown.Both);
							_socket.Close();
						}
					}
					catch (Exception ex)
					{
						Debuger.LogError("close socket error :" + ex.Message);
					}
					finally
					{
						OnDisConnect();
					}
				}
				else
				{
					Debuger.LogWarning("close socket fail,socket is null");
				}
			}
		}

		private void OnConnect(StateObject state)
		{
			_isConnect = true;
			if (UDSocket.ConnectServer != null)
			{
				UDSocket.ConnectServer(this);
			}
			else
			{
				Debuger.Log("ConnectedServer is null !");
			}
			RecvMsg(state);
		}

		private void OnDisConnect()
		{
			if (!_isConnect)
			{
				Debuger.Log("已经在断开状态");
				return;
			}
			_isConnect = false;
			Common.SafeCall(delegate
			{
				_socket = null;
				if (UDSocket.DisConnectServer != null)
				{
					UDSocket.DisConnectServer(this);
				}
			});
		}

		private void OnConnectError()
		{
			Common.SafeCall(delegate
			{
				_socket = null;
				if (UDSocket.ConnectError != null)
				{
					UDSocket.ConnectError(this);
				}
			});
		}

		public bool SendMsg(byte[] bytes, int len)
		{
			if (len <= 0)
			{
				return false;
			}
			if (!_isConnect || _socket == null)
			{
				Debuger.LogError("not connecting srv!");
				Close();
				return false;
			}
			try
			{
				if (_sendCallback == null)
				{
					_sendCallback = SendCallback;
				}
				_socket.BeginSend(bytes, 0, len, SocketFlags.None, _sendCallback, _socket);
				return true;
			}
			catch (SocketException ex)
			{
				Debuger.LogError("send msg SocketException error : " + ex.Message);
				Close();
				return false;
			}
			catch (NullReferenceException ex2)
			{
				Debuger.LogError("send msg NullReferenceException error : " + ex2.Message);
				Close();
				return false;
			}
		}

		public void RecvMsg(StateObject state)
		{
			if (_receiveCallback == null)
			{
				_receiveCallback = ReceiveCallback;
			}
			_socket.BeginReceive(state.buffer, state.recvSize, state.recvBuffer - state.recvSize, SocketFlags.None, _receiveCallback, state);
		}

		protected void ConnectCallback(IAsyncResult ar)
		{
			StateObject stateObject = (StateObject)ar.AsyncState;
			Socket socket = stateObject.socket;
			if (socket == null)
			{
				Debuger.LogError("Error : socket == null");
				return;
			}
			bool flag = false;
			try
			{
				socket.EndConnect(ar);
				flag = true;
			}
			catch (SocketException ex)
			{
				Debuger.LogError("connect call back is error : " + ex.Message);
				if (!flag)
				{
					OnConnectError();
				}
				return;
			}
			finally
			{
				Debuger.Log("conn server " + stateObject.addr.ip + ":" + stateObject.addr.port + " " + flag);
			}
			OnConnect(stateObject);
		}

		protected void ReceiveCallback(IAsyncResult ar)
		{
			StateObject stateObject = (StateObject)ar.AsyncState;
			Socket socket = stateObject.socket;
			if (socket != null && socket.Connected && _isConnect)
			{
				try
				{
					int num = socket.EndReceive(ar);
					if (num == 0)
					{
						Debuger.Log("接收数据正常退出");
					}
					else if (num < 0)
					{
						Debuger.LogError("Error : the data is < 1 bit");
					}
					else
					{
						if (UDSocket.NetDataRecv != null)
						{
							UDSocket.NetDataRecv(this, stateObject.buffer, num);
						}
						Array.Clear(stateObject.buffer, 0, num);
						RecvMsg(stateObject);
					}
				}
				catch (SocketException ex)
				{
					Debuger.LogError("recv msg error : " + ex.Message);
					Close();
				}
				catch (ObjectDisposedException ex2)
				{
					Debuger.LogError("object disposed exception :" + ex2.Message);
					Close();
				}
				finally
				{
				}
			}
		}

		private void SendCallback(IAsyncResult ar)
		{
			try
			{
				Socket socket = (Socket)ar.AsyncState;
				int num = socket.EndSend(ar);
				if (num <= 0)
				{
					Debuger.LogError("Error ：send data <= zero");
					Close();
				}
				else if (UDSocket.NetDataSend != null)
				{
					UDSocket.NetDataSend(this, num);
				}
			}
			catch (Exception ex)
			{
				Debuger.LogWarning("send msg call back error : " + ex.Message);
				Close();
			}
			finally
			{
			}
		}
	}
}
